/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* vim: set ts=8 sts=2 et sw=2 tw=80: *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#ifndef mozilla_dom_workers_workerprivate_h__#define mozilla_dom_workers_workerprivate_h__#include"Workers.h"#include"js/CharacterEncoding.h"#include"nsIContentPolicy.h"#include"nsIContentSecurityPolicy.h"#include"nsILoadGroup.h"#include"nsIWorkerDebugger.h"#include"nsPIDOMWindow.h"#include"mozilla/Assertions.h"#include"mozilla/Attributes.h"#include"mozilla/CondVar.h"#include"mozilla/ConsoleReportCollector.h"#include"mozilla/DOMEventTargetHelper.h"#include"mozilla/Move.h"#include"mozilla/TimeStamp.h"#include"mozilla/dom/BindingDeclarations.h"#include"nsAutoPtr.h"#include"nsCycleCollectionParticipant.h"#include"nsDataHashtable.h"#include"nsHashKeys.h"#include"nsRefPtrHashtable.h"#include"nsString.h"#include"nsTArray.h"#include"nsThreadUtils.h"#include"nsTObserverArray.h"#include"Queue.h"#include"WorkerHolder.h"#ifdef XP_WIN#undef PostMessage#endifclassnsIChannel;classnsIConsoleReportCollector;classnsIDocument;classnsIEventTarget;classnsIPrincipal;classnsIScriptContext;classnsIScriptTimeoutHandler;classnsISerialEventTarget;classnsISerializable;classnsIThread;classnsIThreadInternal;classnsITimer;classnsIURI;template<classT>classnsMainThreadPtrHandle;namespaceJS{structRuntimeStats;}// namespace JSnamespacemozilla{classThrottledEventQueue;namespacedom{classFunction;classMessagePort;classMessagePortIdentifier;classPromiseNativeHandler;classStructuredCloneHolder;classWorkerDebuggerGlobalScope;classWorkerGlobalScope;structWorkerOptions;}// namespace domnamespaceipc{classPrincipalInfo;}// namespace ipc}// namespace mozillastructPRThread;classReportDebuggerErrorRunnable;classPostDebuggerMessageRunnable;BEGIN_WORKERS_NAMESPACEclassAutoSyncLoopHolder;classSharedWorker;classServiceWorkerClientInfo;classWorkerControlEventTarget;classWorkerControlRunnable;classWorkerDebugger;classWorkerPrivate;classWorkerRunnable;classWorkerThread;// SharedMutex is a small wrapper around an (internal) reference-counted Mutex// object. It exists to avoid changing a lot of code to use Mutex* instead of// Mutex&.classSharedMutex{typedefmozilla::MutexMutex;classRefCountedMutexfinal:publicMutex{public:explicitRefCountedMutex(constchar*aName):Mutex(aName){}NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMutex)private:~RefCountedMutex(){}};RefPtr<RefCountedMutex>mMutex;public:explicitSharedMutex(constchar*aName):mMutex(newRefCountedMutex(aName)){}SharedMutex(SharedMutex&aOther):mMutex(aOther.mMutex){}operatorMutex&(){return*mMutex;}operatorconstMutex&()const{return*mMutex;}voidAssertCurrentThreadOwns()const{mMutex->AssertCurrentThreadOwns();}};classWorkerErrorBase{public:nsStringmMessage;nsStringmFilename;uint32_tmLineNumber;uint32_tmColumnNumber;uint32_tmErrorNumber;WorkerErrorBase():mLineNumber(0),mColumnNumber(0),mErrorNumber(0){}voidAssignErrorBase(JSErrorBase*aReport);};classWorkerErrorNote:publicWorkerErrorBase{public:voidAssignErrorNote(JSErrorNotes::Note*aNote);};classWorkerErrorReport:publicWorkerErrorBase{public:nsStringmLine;uint32_tmFlags;JSExnTypemExnType;boolmMutedError;nsTArray<WorkerErrorNote>mNotes;WorkerErrorReport():mFlags(0),mExnType(JSEXN_ERR),mMutedError(false){}voidAssignErrorReport(JSErrorReport*aReport);};template<classDerived>classWorkerPrivateParent:publicDOMEventTargetHelper{protected:classEventTarget;friendclassEventTarget;typedefmozilla::ipc::PrincipalInfoPrincipalInfo;public:structLocationInfo{nsCStringmHref;nsCStringmProtocol;nsCStringmHost;nsCStringmHostname;nsCStringmPort;nsCStringmPathname;nsCStringmSearch;nsCStringmHash;nsStringmOrigin;};protected:typedefmozilla::ErrorResultErrorResult;SharedMutexmMutex;mozilla::CondVarmCondVar;// Protected by mMutex.RefPtr<EventTarget>mEventTarget;nsTArray<RefPtr<WorkerRunnable>>mPreStartRunnables;private:WorkerPrivate*mParent;nsStringmScriptURL;// This is the worker name for shared workers and dedicated workers.nsStringmWorkerName;// This is the worker scope for service workers.nsCStringmServiceWorkerScope;LocationInfomLocationInfo;// The lifetime of these objects within LoadInfo is managed explicitly;// they do not need to be cycle collected.WorkerLoadInfomLoadInfo;Atomic<bool>mLoadingWorkerScript;// Only used for top level workers.nsTArray<nsCOMPtr<nsIRunnable>>mQueuedRunnables;// Protected by mMutex.JSSettingsmJSSettings;// Only touched on the parent thread (currently this is always the main// thread as SharedWorkers are always top-level).nsTArray<RefPtr<SharedWorker>>mSharedWorkers;uint64_tmBusyCount;// SharedWorkers may have multiple windows paused, so this must be// a count instead of just a boolean.uint32_tmParentWindowPausedDepth;StatusmParentStatus;boolmParentFrozen;boolmIsChromeWorker;boolmMainThreadObjectsForgotten;// mIsSecureContext is set once in our constructor; after that it can be read// from various threads. We could make this const if we were OK with setting// it in the initializer list via calling some function that takes all sorts// of state (loadinfo, worker type, parent).//// It's a bit unfortunate that we have to have an out-of-band boolean for// this, but we need access to this state from the parent thread, and we can't// use our global object's secure state there.boolmIsSecureContext;WorkerTypemWorkerType;TimeStampmCreationTimeStamp;DOMHighResTimeStampmCreationTimeHighRes;protected:// The worker is owned by its thread, which is represented here. This is set// in Construct() and emptied by WorkerFinishedRunnable, and conditionally// traversed by the cycle collector if the busy count is zero.RefPtr<WorkerPrivate>mSelfRef;WorkerPrivateParent(WorkerPrivate*aParent,constnsAString&aScriptURL,boolaIsChromeWorker,WorkerTypeaWorkerType,constnsAString&aWorkerName,constnsACString&aServiceWorkerScope,WorkerLoadInfo&aLoadInfo);~WorkerPrivateParent();private:Derived*ParentAsWorkerPrivate()const{returnstatic_cast<Derived*>(const_cast<WorkerPrivateParent*>(this));}boolNotifyPrivate(StatusaStatus);boolTerminatePrivate(){returnNotifyPrivate(Terminating);}voidPostMessageInternal(JSContext*aCx,JS::Handle<JS::Value>aMessage,constSequence<JSObject*>&aTransferable,ErrorResult&aRv);nsresultDispatchPrivate(already_AddRefed<WorkerRunnable>aRunnable,nsIEventTarget*aSyncLoopTarget);public:virtualJSObject*WrapObject(JSContext*aCx,JS::Handle<JSObject*>aGivenProto)override;NS_DECL_ISUPPORTS_INHERITEDNS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(WorkerPrivateParent,DOMEventTargetHelper)voidEnableDebugger();voidDisableDebugger();voidClearSelfRef(){AssertIsOnParentThread();MOZ_ASSERT(mSelfRef);mSelfRef=nullptr;}nsresultDispatch(already_AddRefed<WorkerRunnable>aRunnable){returnDispatchPrivate(Move(aRunnable),nullptr);}nsresultDispatchControlRunnable(already_AddRefed<WorkerControlRunnable>aWorkerControlRunnable);nsresultDispatchDebuggerRunnable(already_AddRefed<WorkerRunnable>aDebuggerRunnable);already_AddRefed<WorkerRunnable>MaybeWrapAsWorkerRunnable(already_AddRefed<nsIRunnable>aRunnable);already_AddRefed<nsISerialEventTarget>GetEventTarget();// May be called on any thread...boolStart();// Called on the parent thread.boolNotify(StatusaStatus){returnNotifyPrivate(aStatus);}boolCancel(){returnNotify(Canceling);}boolKill(){returnNotify(Killing);}// We can assume that an nsPIDOMWindow will be available for Freeze, Thaw// as these are only used for globals going in and out of the bfcache.//// XXXbz: This is a bald-faced lie given the uses in RegisterSharedWorker and// CloseSharedWorkersForWindow, which pass null for aWindow to Thaw and Freeze// respectively. See bug 1251722.boolFreeze(nsPIDOMWindowInner*aWindow);boolThaw(nsPIDOMWindowInner*aWindow);// When we debug a worker, we want to disconnect the window and the worker// communication. This happens calling this method.// Note: this method doesn't suspend the worker! Use Freeze/Thaw instead.voidParentWindowPaused();voidParentWindowResumed();boolTerminate(){AssertIsOnParentThread();returnTerminatePrivate();}boolClose();boolModifyBusyCount(boolaIncrease);boolProxyReleaseMainThreadObjects();voidPostMessage(JSContext*aCx,JS::Handle<JS::Value>aMessage,constSequence<JSObject*>&aTransferable,ErrorResult&aRv);voidUpdateContextOptions(constJS::ContextOptions&aContextOptions);voidUpdateLanguages(constnsTArray<nsString>&aLanguages);voidUpdatePreference(WorkerPreferenceaPref,boolaValue);voidUpdateJSWorkerMemoryParameter(JSGCParamKeykey,uint32_tvalue);#ifdef JS_GC_ZEALvoidUpdateGCZeal(uint8_taGCZeal,uint32_taFrequency);#endifvoidGarbageCollect(boolaShrinking);voidCycleCollect(boolaDummy);voidOfflineStatusChangeEvent(boolaIsOffline);voidMemoryPressure(boolaDummy);boolRegisterSharedWorker(SharedWorker*aSharedWorker,MessagePort*aPort);voidBroadcastErrorToSharedWorkers(JSContext*aCx,constWorkerErrorReport*aReport,boolaIsErrorEvent);voidWorkerScriptLoaded();voidQueueRunnable(nsIRunnable*aRunnable){AssertIsOnParentThread();mQueuedRunnables.AppendElement(aRunnable);}WorkerPrivate*GetParent()const{returnmParent;}boolIsFrozen()const{AssertIsOnParentThread();returnmParentFrozen;}boolIsParentWindowPaused()const{AssertIsOnParentThread();returnmParentWindowPausedDepth>0;}boolIsAcceptingEvents(){AssertIsOnParentThread();MutexAutoLocklock(mMutex);returnmParentStatus<Terminating;}StatusParentStatus()const{mMutex.AssertCurrentThreadOwns();returnmParentStatus;}nsIScriptContext*GetScriptContext()const{AssertIsOnMainThread();returnmLoadInfo.mScriptContext;}constnsString&ScriptURL()const{returnmScriptURL;}constnsCString&Domain()const{returnmLoadInfo.mDomain;}boolIsFromWindow()const{returnmLoadInfo.mFromWindow;}nsLoadFlagsGetLoadFlags()const{returnmLoadInfo.mLoadFlags;}uint64_tWindowID()const{returnmLoadInfo.mWindowID;}uint64_tServiceWorkerID()const{returnmLoadInfo.mServiceWorkerID;}constnsCString&ServiceWorkerScope()const{MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker());returnmServiceWorkerScope;}nsIURI*GetBaseURI()const{AssertIsOnMainThread();returnmLoadInfo.mBaseURI;}voidSetBaseURI(nsIURI*aBaseURI);nsIURI*GetResolvedScriptURI()const{AssertIsOnMainThread();returnmLoadInfo.mResolvedScriptURI;}constnsString&ServiceWorkerCacheName()const{MOZ_ASSERT(IsServiceWorker());AssertIsOnMainThread();returnmLoadInfo.mServiceWorkerCacheName;}constChannelInfo&GetChannelInfo()const{returnmLoadInfo.mChannelInfo;}voidSetChannelInfo(constChannelInfo&aChannelInfo){AssertIsOnMainThread();MOZ_ASSERT(!mLoadInfo.mChannelInfo.IsInitialized());MOZ_ASSERT(aChannelInfo.IsInitialized());mLoadInfo.mChannelInfo=aChannelInfo;}voidInitChannelInfo(nsIChannel*aChannel){mLoadInfo.mChannelInfo.InitFromChannel(aChannel);}voidInitChannelInfo(constChannelInfo&aChannelInfo){mLoadInfo.mChannelInfo=aChannelInfo;}// This is used to handle importScripts(). When the worker is first loaded// and executed, it happens in a sync loop. At this point it sets// mLoadingWorkerScript to true. importScripts() calls that occur during the// execution run in nested sync loops and so this continues to return true,// leading to these scripts being cached offline.// mLoadingWorkerScript is set to false when the top level loop ends.// importScripts() in function calls or event handlers are always fetched// from the network.boolLoadScriptAsPartOfLoadingServiceWorkerScript(){MOZ_ASSERT(IsServiceWorker());returnmLoadingWorkerScript;}voidSetLoadingWorkerScript(boolaLoadingWorkerScript){// any threadMOZ_ASSERT(IsServiceWorker());mLoadingWorkerScript=aLoadingWorkerScript;}TimeStampCreationTimeStamp()const{returnmCreationTimeStamp;}DOMHighResTimeStampCreationTime()const{returnmCreationTimeHighRes;}DOMHighResTimeStampTimeStampToDOMHighRes(constTimeStamp&aTimeStamp)const{MOZ_ASSERT(!aTimeStamp.IsNull());TimeDurationduration=aTimeStamp-mCreationTimeStamp;returnduration.ToMilliseconds();}nsIPrincipal*GetPrincipal()const{AssertIsOnMainThread();returnmLoadInfo.mPrincipal;}constnsAString&Origin()const{returnmLoadInfo.mOrigin;}nsILoadGroup*GetLoadGroup()const{AssertIsOnMainThread();returnmLoadInfo.mLoadGroup;}// This method allows the principal to be retrieved off the main thread.// Principals are main-thread objects so the caller must ensure that all// access occurs on the main thread.nsIPrincipal*GetPrincipalDontAssertMainThread()const{returnmLoadInfo.mPrincipal;}nsresultSetPrincipalOnMainThread(nsIPrincipal*aPrincipal,nsILoadGroup*aLoadGroup);nsresultSetPrincipalFromChannel(nsIChannel*aChannel);#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLEDboolFinalChannelPrincipalIsValid(nsIChannel*aChannel);boolPrincipalURIMatchesScriptURL();#endifboolUsesSystemPrincipal()const{returnmLoadInfo.mPrincipalIsSystem;}constPrincipalInfo&GetPrincipalInfo()const{return*mLoadInfo.mPrincipalInfo;}already_AddRefed<nsIChannel>ForgetWorkerChannel(){AssertIsOnMainThread();returnmLoadInfo.mChannel.forget();}nsIDocument*GetDocument()const;nsPIDOMWindowInner*GetWindow(){AssertIsOnMainThread();returnmLoadInfo.mWindow;}nsIContentSecurityPolicy*GetCSP()const{AssertIsOnMainThread();returnmLoadInfo.mCSP;}voidSetCSP(nsIContentSecurityPolicy*aCSP);nsresultSetCSPFromHeaderValues(constnsACString&aCSPHeaderValue,constnsACString&aCSPReportOnlyHeaderValue);voidSetReferrerPolicyFromHeaderValue(constnsACString&aReferrerPolicyHeaderValue);net::ReferrerPolicyGetReferrerPolicy()const{returnmLoadInfo.mReferrerPolicy;}voidSetReferrerPolicy(net::ReferrerPolicyaReferrerPolicy){mLoadInfo.mReferrerPolicy=aReferrerPolicy;}boolIsEvalAllowed()const{returnmLoadInfo.mEvalAllowed;}voidSetEvalAllowed(boolaEvalAllowed){mLoadInfo.mEvalAllowed=aEvalAllowed;}boolGetReportCSPViolations()const{returnmLoadInfo.mReportCSPViolations;}voidSetReportCSPViolations(boolaReport){mLoadInfo.mReportCSPViolations=aReport;}boolXHRParamsAllowed()const{returnmLoadInfo.mXHRParamsAllowed;}voidSetXHRParamsAllowed(boolaAllowed){mLoadInfo.mXHRParamsAllowed=aAllowed;}LocationInfo&GetLocationInfo(){returnmLocationInfo;}voidCopyJSSettings(JSSettings&aSettings){mozilla::MutexAutoLocklock(mMutex);aSettings=mJSSettings;}voidCopyJSCompartmentOptions(JS::CompartmentOptions&aOptions){mozilla::MutexAutoLocklock(mMutex);aOptions=IsChromeWorker()?mJSSettings.chrome.compartmentOptions:mJSSettings.content.compartmentOptions;}// The ability to be a chrome worker is orthogonal to the type of// worker [Dedicated|Shared|Service].boolIsChromeWorker()const{returnmIsChromeWorker;}WorkerTypeType()const{returnmWorkerType;}boolIsDedicatedWorker()const{returnmWorkerType==WorkerTypeDedicated;}boolIsSharedWorker()const{returnmWorkerType==WorkerTypeShared;}boolIsServiceWorker()const{returnmWorkerType==WorkerTypeService;}nsContentPolicyTypeContentPolicyType()const{returnContentPolicyType(mWorkerType);}staticnsContentPolicyTypeContentPolicyType(WorkerTypeaWorkerType){switch(aWorkerType){caseWorkerTypeDedicated:returnnsIContentPolicy::TYPE_INTERNAL_WORKER;caseWorkerTypeShared:returnnsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER;caseWorkerTypeService:returnnsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER;default:MOZ_ASSERT_UNREACHABLE("Invalid worker type");returnnsIContentPolicy::TYPE_INVALID;}}constnsString&WorkerName()const{returnmWorkerName;}boolIsStorageAllowed()const{returnmLoadInfo.mStorageAllowed;}constOriginAttributes&GetOriginAttributes()const{returnmLoadInfo.mOriginAttributes;}// Determine if the SW testing per-window flag is set by devtoolsboolServiceWorkersTestingInWindow()const{returnmLoadInfo.mServiceWorkersTestingInWindow;}voidGetAllSharedWorkers(nsTArray<RefPtr<SharedWorker>>&aSharedWorkers);voidCloseSharedWorkersForWindow(nsPIDOMWindowInner*aWindow);voidCloseAllSharedWorkers();voidUpdateOverridenLoadGroup(nsILoadGroup*aBaseLoadGroup);already_AddRefed<nsIRunnable>StealLoadFailedAsyncRunnable(){returnmLoadInfo.mLoadFailedAsyncRunnable.forget();}voidFlushReportsToSharedWorkers(nsIConsoleReportCollector*aReporter);IMPL_EVENT_HANDLER(message)IMPL_EVENT_HANDLER(error)// Check whether this worker is a secure context. For use from the parent// thread only; the canonical "is secure context" boolean is stored on the// compartment of the worker global. The only reason we don't// AssertIsOnParentThread() here is so we can assert that this value matches// the one on the compartment, which has to be done from the worker thread.boolIsSecureContext()const{returnmIsSecureContext;}#ifdef DEBUGvoidAssertIsOnParentThread()const;voidAssertInnerWindowIsCorrect()const;#elsevoidAssertIsOnParentThread()const{}voidAssertInnerWindowIsCorrect()const{}#endif#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLEDboolPrincipalIsValid()const;#endif};classWorkerDebugger:publicnsIWorkerDebugger{friendclass::ReportDebuggerErrorRunnable;friendclass::PostDebuggerMessageRunnable;WorkerPrivate*mWorkerPrivate;boolmIsInitialized;nsTArray<nsCOMPtr<nsIWorkerDebuggerListener>>mListeners;public:explicitWorkerDebugger(WorkerPrivate*aWorkerPrivate);NS_DECL_ISUPPORTSNS_DECL_NSIWORKERDEBUGGERvoidAssertIsOnParentThread();voidClose();voidPostMessageToDebugger(constnsAString&aMessage);voidReportErrorToDebugger(constnsAString&aFilename,uint32_taLineno,constnsAString&aMessage);private:virtual~WorkerDebugger();voidPostMessageToDebuggerOnMainThread(constnsAString&aMessage);voidReportErrorToDebuggerOnMainThread(constnsAString&aFilename,uint32_taLineno,constnsAString&aMessage);};classWorkerPrivate:publicWorkerPrivateParent<WorkerPrivate>{friendclassWorkerHolder;friendclassWorkerPrivateParent<WorkerPrivate>;typedefWorkerPrivateParent<WorkerPrivate>ParentType;friendclassAutoSyncLoopHolder;structTimeoutInfo;classMemoryReporter;friendclassMemoryReporter;friendclassWorkerThread;enumGCTimerMode{PeriodicTimer=0,IdleTimer,NoTimer};boolmDebuggerRegistered;WorkerDebugger*mDebugger;Queue<WorkerControlRunnable*,4>mControlQueue;Queue<WorkerRunnable*,4>mDebuggerQueue;// Touched on multiple threads, protected with mMutex.JSContext*mJSContext;RefPtr<WorkerCrossThreadDispatcher>mCrossThreadDispatcher;nsTArray<nsCOMPtr<nsIRunnable>>mUndispatchedRunnablesForSyncLoop;RefPtr<WorkerThread>mThread;PRThread*mPRThread;// Things touched on worker thread only.RefPtr<WorkerGlobalScope>mScope;RefPtr<WorkerDebuggerGlobalScope>mDebuggerScope;nsTArray<ParentType*>mChildWorkers;nsTObserverArray<WorkerHolder*>mHolders;uint32_tmNumHoldersPreventingShutdownStart;nsTArray<nsAutoPtr<TimeoutInfo>>mTimeouts;uint32_tmDebuggerEventLoopLevel;RefPtr<ThrottledEventQueue>mMainThreadThrottledEventQueue;nsCOMPtr<nsIEventTarget>mMainThreadEventTarget;RefPtr<WorkerControlEventTarget>mWorkerControlEventTarget;structSyncLoopInfo{explicitSyncLoopInfo(EventTarget*aEventTarget);RefPtr<EventTarget>mEventTarget;boolmCompleted;boolmResult;#ifdef DEBUGboolmHasRun;#endif};// This is only modified on the worker thread, but in DEBUG builds// AssertValidSyncLoop function iterates it on other threads. Therefore// modifications are done with mMutex held *only* in DEBUG builds.nsTArray<nsAutoPtr<SyncLoopInfo>>mSyncLoopStack;nsCOMPtr<nsITimer>mTimer;nsCOMPtr<nsITimerCallback>mTimerRunnable;nsCOMPtr<nsITimer>mGCTimer;RefPtr<MemoryReporter>mMemoryReporter;// fired on the main thread if the worker script fails to loadnsCOMPtr<nsIRunnable>mLoadFailedRunnable;JS::UniqueCharsmDefaultLocale;// nulled during worker JSContext initTimeStampmKillTime;uint32_tmErrorHandlerRecursionCount;uint32_tmNextTimeoutId;StatusmStatus;boolmFrozen;boolmTimerRunning;boolmRunningExpiredTimeouts;boolmPendingEventQueueClearing;boolmCancelAllPendingRunnables;boolmPeriodicGCTimerRunning;boolmIdleGCTimerRunning;boolmWorkerScriptExecutedSuccessfully;boolmFetchHandlerWasAdded;boolmPreferences[WORKERPREF_COUNT];boolmOnLine;protected:~WorkerPrivate();public:staticalready_AddRefed<WorkerPrivate>Constructor(constGlobalObject&aGlobal,constnsAString&aScriptURL,constWorkerOptions&aOptions,ErrorResult&aRv);staticalready_AddRefed<WorkerPrivate>Constructor(constGlobalObject&aGlobal,constnsAString&aScriptURL,boolaIsChromeWorker,WorkerTypeaWorkerType,constnsAString&aWorkerName,WorkerLoadInfo*aLoadInfo,ErrorResult&aRv);staticalready_AddRefed<WorkerPrivate>Constructor(JSContext*aCx,constnsAString&aScriptURL,boolaIsChromeWorker,WorkerTypeaWorkerType,constnsAString&aWorkerName,constnsACString&aServiceWorkerScope,WorkerLoadInfo*aLoadInfo,ErrorResult&aRv);staticboolWorkerAvailable(JSContext*/* unused */,JSObject*/* unused */);enumLoadGroupBehavior{InheritLoadGroup,OverrideLoadGroup};staticnsresultGetLoadInfo(JSContext*aCx,nsPIDOMWindowInner*aWindow,WorkerPrivate*aParent,constnsAString&aScriptURL,boolaIsChromeWorker,LoadGroupBehavioraLoadGroupBehavior,WorkerTypeaWorkerType,WorkerLoadInfo*aLoadInfo);staticvoidOverrideLoadInfoLoadGroup(WorkerLoadInfo&aLoadInfo);boolIsDebuggerRegistered(){AssertIsOnMainThread();// No need to lock here since this is only ever modified by the same thread.returnmDebuggerRegistered;}voidSetIsDebuggerRegistered(boolaDebuggerRegistered){AssertIsOnMainThread();MutexAutoLocklock(mMutex);MOZ_ASSERT(mDebuggerRegistered!=aDebuggerRegistered);mDebuggerRegistered=aDebuggerRegistered;mCondVar.Notify();}voidWaitForIsDebuggerRegistered(boolaDebuggerRegistered){AssertIsOnParentThread();MOZ_ASSERT(!NS_IsMainThread());MutexAutoLocklock(mMutex);while(mDebuggerRegistered!=aDebuggerRegistered){mCondVar.Wait();}}WorkerDebugger*Debugger()const{AssertIsOnMainThread();MOZ_ASSERT(mDebugger);returnmDebugger;}voidSetDebugger(WorkerDebugger*aDebugger){AssertIsOnMainThread();MOZ_ASSERT(mDebugger!=aDebugger);mDebugger=aDebugger;}JS::UniqueCharsAdoptDefaultLocale(){MOZ_ASSERT(mDefaultLocale,"the default locale must have been successfully set for anyone ""to be trying to adopt it");returnMove(mDefaultLocale);}voidDoRunLoop(JSContext*aCx);boolInterruptCallback(JSContext*aCx);boolIsOnCurrentThread();boolCloseInternal(JSContext*aCx){AssertIsOnWorkerThread();returnNotifyInternal(aCx,Closing);}boolFreezeInternal();boolThawInternal();voidTraverseTimeouts(nsCycleCollectionTraversalCallback&aCallback);voidUnlinkTimeouts();boolModifyBusyCountFromWorker(boolaIncrease);boolAddChildWorker(ParentType*aChildWorker);voidRemoveChildWorker(ParentType*aChildWorker);voidPostMessageToParent(JSContext*aCx,JS::Handle<JS::Value>aMessage,constSequence<JSObject*>&aTransferable,ErrorResult&aRv){PostMessageToParentInternal(aCx,aMessage,aTransferable,aRv);}voidPostMessageToParentMessagePort(JSContext*aCx,JS::Handle<JS::Value>aMessage,constSequence<JSObject*>&aTransferable,ErrorResult&aRv);voidEnterDebuggerEventLoop();voidLeaveDebuggerEventLoop();voidPostMessageToDebugger(constnsAString&aMessage);voidSetDebuggerImmediate(Function&aHandler,ErrorResult&aRv);voidReportErrorToDebugger(constnsAString&aFilename,uint32_taLineno,constnsAString&aMessage);boolNotifyInternal(JSContext*aCx,StatusaStatus);voidReportError(JSContext*aCx,JS::ConstUTF8CharsZaToStringResult,JSErrorReport*aReport);staticvoidReportErrorToConsole(constchar*aMessage);int32_tSetTimeout(JSContext*aCx,nsIScriptTimeoutHandler*aHandler,int32_taTimeout,boolaIsInterval,ErrorResult&aRv);voidClearTimeout(int32_taId);boolRunExpiredTimeouts(JSContext*aCx);boolRescheduleTimeoutTimer(JSContext*aCx);voidUpdateContextOptionsInternal(JSContext*aCx,constJS::ContextOptions&aContextOptions);voidUpdateLanguagesInternal(constnsTArray<nsString>&aLanguages);voidUpdatePreferenceInternal(WorkerPreferenceaPref,boolaValue);voidUpdateJSWorkerMemoryParameterInternal(JSContext*aCx,JSGCParamKeykey,uint32_taValue);enumWorkerRanOrNot{WorkerNeverRan=0,WorkerRan};voidScheduleDeletion(WorkerRanOrNotaRanOrNot);boolCollectRuntimeStats(JS::RuntimeStats*aRtStats,boolaAnonymize);#ifdef JS_GC_ZEALvoidUpdateGCZealInternal(JSContext*aCx,uint8_taGCZeal,uint32_taFrequency);#endifvoidGarbageCollectInternal(JSContext*aCx,boolaShrinking,boolaCollectChildren);voidCycleCollectInternal(boolaCollectChildren);voidOfflineStatusChangeEventInternal(boolaIsOffline);voidMemoryPressureInternal();voidSetFetchHandlerWasAdded(){MOZ_ASSERT(IsServiceWorker());AssertIsOnWorkerThread();mFetchHandlerWasAdded=true;}boolFetchHandlerWasAdded()const{MOZ_ASSERT(IsServiceWorker());AssertIsOnWorkerThread();returnmFetchHandlerWasAdded;}JSContext*GetJSContext()const{AssertIsOnWorkerThread();returnmJSContext;}WorkerGlobalScope*GlobalScope()const{AssertIsOnWorkerThread();returnmScope;}WorkerDebuggerGlobalScope*DebuggerGlobalScope()const{AssertIsOnWorkerThread();returnmDebuggerScope;}voidSetThread(WorkerThread*aThread);voidAssertIsOnWorkerThread()const#ifdef DEBUG;#else{}#endifWorkerCrossThreadDispatcher*GetCrossThreadDispatcher();// This may block!voidBeginCTypesCall();// This may block!voidEndCTypesCall();voidBeginCTypesCallback(){// If a callback is beginning then we need to do the exact same thing as// when a ctypes call ends.EndCTypesCall();}voidEndCTypesCallback(){// If a callback is ending then we need to do the exact same thing as// when a ctypes call begins.BeginCTypesCall();}boolConnectMessagePort(JSContext*aCx,MessagePortIdentifier&aIdentifier);WorkerGlobalScope*GetOrCreateGlobalScope(JSContext*aCx);WorkerDebuggerGlobalScope*CreateDebuggerGlobalScope(JSContext*aCx);boolRegisterBindings(JSContext*aCx,JS::Handle<JSObject*>aGlobal);boolRegisterDebuggerBindings(JSContext*aCx,JS::Handle<JSObject*>aGlobal);#define WORKER_SIMPLE_PREF(name, getter, NAME) \ bool \ getter() const \ { \ AssertIsOnWorkerThread(); \ return mPreferences[WORKERPREF_##NAME]; \ }#define WORKER_PREF(name, callback)#include"WorkerPrefs.h"#undef WORKER_SIMPLE_PREF#undef WORKER_PREFboolOnLine()const{AssertIsOnWorkerThread();returnmOnLine;}voidStopSyncLoop(nsIEventTarget*aSyncLoopTarget,boolaResult);boolAllPendingRunnablesShouldBeCanceled()const{returnmCancelAllPendingRunnables;}voidClearMainEventQueue(WorkerRanOrNotaRanOrNot);voidClearDebuggerEventQueue();voidOnProcessNextEvent();voidAfterProcessNextEvent();voidAssertValidSyncLoop(nsIEventTarget*aSyncLoopTarget)#ifdef DEBUG;#else{}#endifvoidSetWorkerScriptExecutedSuccessfully(){AssertIsOnWorkerThread();// Should only be called once!MOZ_ASSERT(!mWorkerScriptExecutedSuccessfully);mWorkerScriptExecutedSuccessfully=true;}// Only valid after CompileScriptRunnable has finished running!boolWorkerScriptExecutedSuccessfully()const{AssertIsOnWorkerThread();returnmWorkerScriptExecutedSuccessfully;}voidMaybeDispatchLoadFailedRunnable();// Get the event target to use when dispatching to the main thread// from this Worker thread. This may be the main thread itself or// a ThrottledEventQueue to the main thread.nsIEventTarget*MainThreadEventTarget();nsresultDispatchToMainThread(nsIRunnable*aRunnable,uint32_taFlags=NS_DISPATCH_NORMAL);nsresultDispatchToMainThread(already_AddRefed<nsIRunnable>aRunnable,uint32_taFlags=NS_DISPATCH_NORMAL);// Get an event target that will dispatch runnables as control runnables on// the worker thread. Implement nsICancelableRunnable if you wish to take// action on cancelation.nsIEventTarget*ControlEventTarget();private:WorkerPrivate(WorkerPrivate*aParent,constnsAString&aScriptURL,boolaIsChromeWorker,WorkerTypeaWorkerType,constnsAString&aWorkerName,constnsACString&aServiceWorkerScope,WorkerLoadInfo&aLoadInfo);boolMayContinueRunning(){AssertIsOnWorkerThread();Statusstatus;{MutexAutoLocklock(mMutex);status=mStatus;}if(status<Terminating){returntrue;}returnfalse;}voidCancelAllTimeouts();enumclassProcessAllControlRunnablesResult{// We did not process anything.Nothing,// We did process something, states may have changed, but we can keep// executing script.MayContinue,// We did process something, and should not continue executing script.Abort};ProcessAllControlRunnablesResultProcessAllControlRunnables(){MutexAutoLocklock(mMutex);returnProcessAllControlRunnablesLocked();}ProcessAllControlRunnablesResultProcessAllControlRunnablesLocked();voidEnableMemoryReporter();voidDisableMemoryReporter();voidWaitForWorkerEvents(PRIntervalTimeinterval=PR_INTERVAL_NO_TIMEOUT);voidPostMessageToParentInternal(JSContext*aCx,JS::Handle<JS::Value>aMessage,constSequence<JSObject*>&aTransferable,ErrorResult&aRv);voidGetAllPreferences(boolaPreferences[WORKERPREF_COUNT])const{AssertIsOnWorkerThread();memcpy(aPreferences,mPreferences,WORKERPREF_COUNT*sizeof(bool));}// If the worker shutdown status is equal or greater then aFailStatus, this// operation will fail and nullptr will be returned. See WorkerHolder.h for// more information about the correct value to use.already_AddRefed<nsIEventTarget>CreateNewSyncLoop(StatusaFailStatus);boolRunCurrentSyncLoop();boolDestroySyncLoop(uint32_taLoopIndex,nsIThreadInternal*aThread=nullptr);voidInitializeGCTimers();voidSetGCTimerMode(GCTimerModeaMode);voidShutdownGCTimers();boolAddHolder(WorkerHolder*aHolder,StatusaFailStatus);voidRemoveHolder(WorkerHolder*aHolder);voidNotifyHolders(JSContext*aCx,StatusaStatus);boolHasActiveHolders(){return!(mChildWorkers.IsEmpty()&&mTimeouts.IsEmpty()&&mHolders.IsEmpty());}};// This class is only used to trick the DOM bindings. We never create// instances of it, and static_casting to it is fine since it doesn't add// anything to WorkerPrivate.classChromeWorkerPrivate:publicWorkerPrivate{public:staticalready_AddRefed<ChromeWorkerPrivate>Constructor(constGlobalObject&aGlobal,constnsAString&aScriptURL,ErrorResult&rv);staticboolWorkerAvailable(JSContext*aCx,JSObject*/* unused */);private:ChromeWorkerPrivate()=delete;ChromeWorkerPrivate(constChromeWorkerPrivate&aRHS)=delete;ChromeWorkerPrivate&operator=(constChromeWorkerPrivate&aRHS)=delete;};WorkerPrivate*GetWorkerPrivateFromContext(JSContext*aCx);WorkerPrivate*GetCurrentThreadWorkerPrivate();boolIsCurrentThreadRunningChromeWorker();JSContext*GetCurrentThreadJSContext();JSObject*GetCurrentThreadWorkerGlobal();classAutoSyncLoopHolder{WorkerPrivate*mWorkerPrivate;nsCOMPtr<nsIEventTarget>mTarget;uint32_tmIndex;public:// See CreateNewSyncLoop() for more information about the correct value to use// for aFailStatus.AutoSyncLoopHolder(WorkerPrivate*aWorkerPrivate,StatusaFailStatus):mWorkerPrivate(aWorkerPrivate),mTarget(aWorkerPrivate->CreateNewSyncLoop(aFailStatus)),mIndex(aWorkerPrivate->mSyncLoopStack.Length()-1){aWorkerPrivate->AssertIsOnWorkerThread();}~AutoSyncLoopHolder(){if(mWorkerPrivate&&mTarget){mWorkerPrivate->AssertIsOnWorkerThread();mWorkerPrivate->StopSyncLoop(mTarget,false);mWorkerPrivate->DestroySyncLoop(mIndex);}}boolRun(){WorkerPrivate*workerPrivate=mWorkerPrivate;mWorkerPrivate=nullptr;workerPrivate->AssertIsOnWorkerThread();returnworkerPrivate->RunCurrentSyncLoop();}nsIEventTarget*GetEventTarget()const{// This can be null if CreateNewSyncLoop() fails.returnmTarget;}};END_WORKERS_NAMESPACE#endif /* mozilla_dom_workers_workerprivate_h__ */